/*
 .tab-list-container[data-target='#tab-panel'] {
 .tab-list {
 .tab
 }
 }
 #tab-panel.tab-panel-container
 */
// 不要使用 Class.prototype = {} 进行原型赋值，会覆盖默认方法
;var DynamicTab = function ($) {

	var NAME = 'dynamicTab';
	var DATA_KEY = 'dynamicTab';
	var EVENT_KEY = '.' + DATA_KEY;
	var DATA_API_KEY = '.data-api';
	var JQUERY_NO_CONFLICT = $.fn[NAME];


	var Default = {
		action: 'tab-action',
		tabListContainer: '.tab-list-container',
		tabList: ' .tab-list',
		tab: ' .tab',
		tabOpener: '',
		tabActiveClass: 'active',
		tabPanelContainer: '.tab-panel-container',
		tabPanel: 'iframe',

		attrUrl: 'href',
		attrDismiss: 'data-dismiss',
		attrTarget: 'data-target',
		tabTemplate: '<a class="tab active" href="{1}">{0}{2}</a>',
		tabClose: '<i class="fa fa-times-circle"></i>',
		panelTemplate: '<iframe src="{0}" width="100%" height="100%" frameborder="0" seamless></iframe>',
	};

	var TabUtil = function ($) {
		function format() {
			var args = arguments;
			var str = args[0];
			return str.replace(/\{(\d+)\}/g, function (s, i) {
				return args[parseInt(i) + 1];
			});
		}

		/**
		 * 累计所有 tab 元素的总宽度
		 * @param elements
		 * @returns {number}
		 */
		function sumWidth(elements) {
			var width = 0;
			$(elements).each(function () {
				// outerWidth: width padding border, true:包含margin
				width += $(this).outerWidth(true);
			});
			return width;
		}

		function splitWithoutEmpty(str) {
			var result = [];
			if (typeof str != 'string') {
				return result;
			}

			var temp = str.split(' ');
			for (var i = 0, j = temp.length; i < j; i++) {
				if (temp[i] != '') {
					result.push(temp[i]);
				}
			}
			return result;
		}

		function htmlToSelector(element) {
			var elem = $(element)[0];
			var result = '';
			if (elem) {
				result += elem.tagName;
				var classArray = splitWithoutEmpty(elem.className);
				for (var i = 0, j = classArray.length; i < j; i++) {
					result += ('.' + classArray[i]);
				}
			}
			return result;
		}

		var TabUtil = {
			format: format,
			sumWidth: sumWidth,
			htmlToSelector: htmlToSelector
		};

		return TabUtil;
	}(jQuery);

	var Event = {
		INSERT: 'insert' + EVENT_KEY,
		CLOSE: 'close' + EVENT_KEY,
		REFRESH: 'refresh' + EVENT_KEY,
		CLICK_DATA_API: 'click' + EVENT_KEY + DATA_API_KEY
	};

	var Action = {
		Left: 'left',
		Right: 'right',
		Refresh: 'refresh',
		Active: 'active',
		CloseCurrent: 'close-current',
		CloseOther: 'close-other',
		CloseAll: 'close-all'
	};

	var Option = {
		Url: 'url',
		Name: 'name',
		Dismiss: 'dismiss'
	};

	//TODO: 各种事件绑定
	var DynamicTab = function () {
		var dataTabAction = '[data-{0}="{1}"]';

		function DynamicTab(element, config) {
			this._element = element;
			this._config = $.extend({}, Default, config);
			this.init();
		}

		//region 原型方法

		/**
		 * 控件初始化，主要是事件绑定
		 */
		DynamicTab.prototype.init = function () {
			var self = this;
			var conf = this._config;
			var elem = this._element;

			// action 绑定
			$(elem).on('click', TabUtil.format(dataTabAction, conf.action, Action.Left), function () {
				return self.scrollTabsLeft();
			}).on('click', TabUtil.format(dataTabAction, conf.action, Action.Right), function () {
				return self.scrollTabsRight();
			}).on('click', TabUtil.format(dataTabAction, conf.action, Action.Refresh), function () {
				return self.refreshTab();
			}).on('click', TabUtil.format(dataTabAction, conf.action, Action.Active), function () {
				return self.scrollToActive();
			}).on('click', TabUtil.format(dataTabAction, conf.action, Action.CloseCurrent), function () {
				self.closeTab(self._getActiveTab());
			}).on('click', TabUtil.format(dataTabAction, conf.action, Action.CloseOther), function () {
				self.closeOtherTabs();
			}).on('click', TabUtil.format(dataTabAction, conf.action, Action.CloseAll), function () {
				self.closeAllTabs();
			}).on('click', TabUtil.htmlToSelector(conf.tabClose), function () {
				return self.closeTab($(this).parents(conf.tab));
			});

			// 选择现有标签页
			$(elem).on('click', conf.tab, function () {
				var opener = $(this);
				return self.openTab({
					'url': opener.attr(conf.attrUrl)
				});
			});

			// 新建标签页
			$(conf.tabOpener).on('click', function () {
				var opener = $(this);
				return self.openTab({
					'url': opener.attr(conf.attrUrl),
					'name': opener.text(),
					'dismiss': opener.attr(conf.attrDismiss)
				});
			});

			//TODO: 处理窗口 resize 事件，避免 tab 无操作时前后效果不一致
		};

		DynamicTab.prototype._scrollDistance = function (marginLeft) {
			$(this._element).find(this._config.tabList).animate({
				'left': marginLeft + 'px'
			}, 'fast');
		};

		DynamicTab.prototype._getAllTabWidth = function () {
			var conf = this._config;
			return TabUtil.sumWidth($(this._element).find(conf.tabListContainer + conf.tabList + conf.tab));
		};

		DynamicTab.prototype._getVisibleTabContainerWidth = function () {
			return $(this._element).find(this._config.tabListContainer).width();
		};

		/**
		 * 由于 tab-list 是绝对定位，那么 left 可正可负
		 * @returns {Number}
		 * @private
		 */
		DynamicTab.prototype._getTabListMarginLeftValue = function () {
			return parseInt($(this._element).find(this._config.tabList).css('left'));
		};

		/**
		 * 获取第一个可见的 tab 项
		 */
		DynamicTab.prototype._getFirstVisibleTab = function () {
			var conf = this._config;
			var marginLeftValue = this._getTabListMarginLeftValue();
			var currentTab = $(this._element).find(conf.tab + ':first');
			var offsetVal = 0;
			while ((offsetVal + $(currentTab).outerWidth(true)) <= -marginLeftValue) {
				offsetVal += $(currentTab).outerWidth(true);
				currentTab = $(currentTab).next();
			}

			return currentTab;
		};

		DynamicTab.prototype._getActiveTab = function () {
			return $(this._element).find(this._config.tab + '.' + this._config.tabActiveClass);
		};

		DynamicTab.prototype._enableDismiss = function (tab) {
			return $(tab).html().indexOf(this._config.tabClose) > -1;
		};

		DynamicTab.prototype._getTargetTabPanelContainer = function () {
			var conf = this._config;
			var target = $($(this._element).find(conf.tabListContainer).attr(conf.attrTarget));
			if (target.length > 0) {
				return target;
			} else {
				return $(conf.tabPanelContainer);
			}
		};

		DynamicTab.prototype._findTabByUrl = function (url) {
			return $(this._element).find(this._config.tabListContainer)
			.find(this._config.tab + TabUtil.format('[{0}="{1}"]', this._config.attrUrl, url));
		};

		DynamicTab.prototype._findPanelByUrl = function (url) {
			return this._getTargetTabPanelContainer().find(this._config.tabPanel + TabUtil.format('[src="{0}"]', url));
		};

		/**
		 * 滚动到指定选项卡
		 * @param element
		 */
		DynamicTab.prototype.scrollToTab = function (element) {
			var conf = this._config;
			var leftWidth = TabUtil.sumWidth($(element).prevAll());
			var rightWidth = TabUtil.sumWidth($(element).nextAll());
			var visibleTabContainerWidth = this._getVisibleTabContainerWidth();
			var totalTabItemWidth = this._getAllTabWidth();
			var tabWidth = $(element).outerWidth(true);
			var scrollLeft = 0;
			if (totalTabItemWidth < visibleTabContainerWidth) {
				scrollLeft = 0;
			} else if (rightWidth <= (visibleTabContainerWidth - tabWidth - $(element).next().outerWidth(true))) {
				if ((visibleTabContainerWidth - $(element).next().outerWidth(true)) > rightWidth) {
					scrollLeft = leftWidth;
					var tabElement = element;
					while ((scrollLeft - $(tabElement).outerWidth(true)) > ($(conf.tabList).outerWidth() - visibleTabContainerWidth)) {
						scrollLeft -= $(tabElement).prev().outerWidth();
						tabElement = $(tabElement).prev();
					}
				}
			} else if (leftWidth > (visibleTabContainerWidth - $(element).outerWidth(true) - $(element).prev().outerWidth(true))) {
				scrollLeft = leftWidth - $(element).prev().outerWidth(true);
			}

			this._scrollDistance(-scrollLeft);
		};

		DynamicTab.prototype.scrollTabsLeft = function () {
			var visibleTabContainerWidth = this._getVisibleTabContainerWidth();
			if (this._getAllTabWidth() < visibleTabContainerWidth) {
				return false;
			}

			var offset = 0, scrollLeft = 0;
			var tab = this._getFirstVisibleTab();
			if (TabUtil.sumWidth($(tab).prevAll()) > visibleTabContainerWidth) {
				while (tab.length > 0 && ((offset + $(tab).outerWidth(true)) < visibleTabContainerWidth)) {
					offset += $(tab).outerWidth(true);
					tab = $(tab).prev();
				}

				scrollLeft = TabUtil.sumWidth($(tab).prevAll());
			}

			this._scrollDistance(-scrollLeft);
		};

		DynamicTab.prototype.scrollTabsRight = function () {
			var visibleTabContainerWidth = this._getVisibleTabContainerWidth();

			if (this._getAllTabWidth() < visibleTabContainerWidth) {
				return false;
			}

			var offset = 0, scrollLeft;
			var tab = this._getFirstVisibleTab();
			while (tab.length > 0 && ((offset + $(tab).outerWidth(true)) < visibleTabContainerWidth)) {
				offset += $(tab).outerWidth(true);
				tab = $(tab).next();
			}

			scrollLeft = TabUtil.sumWidth($(tab).prevAll());
			if (scrollLeft > 0) {
				this._scrollDistance(-scrollLeft);
			}
		};

		DynamicTab.prototype.scrollToActive = function () {
			this.scrollToTab(this._getActiveTab());
		};


		DynamicTab.prototype.openTabByTag = function (selector) {
			var opener = $(selector);
			var options = {
				'url': opener.attr(this._config.attrUrl),
				'name': opener.text(),
				'dismiss': opener.attr(this._config.attrDismiss)
			};
			return this.openTab(options);
		};

		/**
		 * 打开标签页，如果有相同 url，激活滚动到该 url。如果没有相同的 url，打开新的标签页。
		 */
		DynamicTab.prototype.openTab = function (options) {
			var conf = this._config,
					elem = this._element,
					dataUrl = options[Option.Url];

			var targetTab = this._findTabByUrl(dataUrl);
			if ($(targetTab).length > 0) {
				if (targetTab.hasClass(conf.tabActiveClass)) {
					this.scrollToTab(targetTab);
				} else {
					var targetPanel = this._findPanelByUrl(dataUrl);

					$(targetTab).addClass(conf.tabActiveClass).siblings(conf.tab).removeClass(conf.tabActiveClass);
					$(targetPanel).show().siblings(conf.tabPanel).hide();

					this.scrollToTab($(targetTab));
				}
			} else {
				var dataName = options[Option.Name];
				var dataDismiss = options[Option.Dismiss];
				var dismiss = dataDismiss == null || dataDismiss.toString() !== 'false';
				var tab = TabUtil.format(conf.tabTemplate, dataName, dataUrl, dismiss ? conf.tabClose : '');
				var panel = TabUtil.format(conf.panelTemplate, dataUrl);
				var targetTabPanelContainer = this._getTargetTabPanelContainer();

				$(elem).find(conf.tab).removeClass(conf.tabActiveClass);
				$(elem).find(conf.tabList).append(tab);
				targetTabPanelContainer.find(conf.tabPanel).hide();
				targetTabPanelContainer.append(panel);

				this.scrollToActive();
			}

			return false;
		};

		DynamicTab.prototype.closeTab = function (tabElement) {
			var tab = $(tabElement);
			if (!this._enableDismiss(tab)) {
				return false;
			}

			var conf = this._config;
			var closeUrl = $(tab).attr(conf.attrUrl);
			var panel = this._findPanelByUrl(closeUrl);
			var activeTab, activePanel;

			if ($(tab).hasClass(conf.tabActiveClass)) {
				if ($(tab).next(conf.tab).length) {
					activeTab = $(tab).next(conf.tab + ':eq(0)').addClass(conf.tabActiveClass);
				} else if ($(tab).prev(conf.tab).length) {
					activeTab = $(tab).prev(conf.tab + ':last').addClass(conf.tabActiveClass);
				}

				if (activeTab) {
					activePanel = this._findPanelByUrl(activeTab.attr(conf.attrUrl));
					if (activePanel.length > 0) {
						$(activePanel).show().siblings(conf.tabPanel).hide();
					}

					this.scrollToTab(activeTab);
				}
			}

			$(tab).remove();
			$(panel).remove();
			return false;
		};

		DynamicTab.prototype.closeAllTabs = function () {
			var conf = this._config;
			var elem = this._element;
			var $this = this;
			$(elem).find(conf.tab).has(TabUtil.htmlToSelector(conf.tabClose)).each(function () {
				$this._findPanelByUrl($(this).attr(conf.attrUrl)).remove();
				$(this).remove();
			});

			var activeTab = $(elem).find(conf.tab + ':first').addClass(conf.tabActiveClass);
			var activePanel = this._findPanelByUrl(activeTab.attr(conf.attrUrl));
			if (activePanel.length > 0) {
				$(activePanel).show().siblings(conf.tabPanel).hide();
			}

			this.scrollToTab(activeTab);
		};

		DynamicTab.prototype.closeOtherTabs = function () {
			var conf = this._config;
			var elem = this._element;
			var $this = this;
			$(elem).find(conf.tab).has(TabUtil.htmlToSelector(conf.tabClose)).not('.' + conf.tabActiveClass).each(function () {
				$this._findPanelByUrl($(this).attr(conf.attrUrl)).remove();
				$(this).remove();
			});

			$this._scrollDistance(0);
		};

		DynamicTab.prototype.refreshTab = function () {
			var panel = this._getTargetTabPanelContainer().find(this._config.tabPanel + ':visible');
			$(panel).attr('src', $(panel).attr('src'));
		};

		//endregion

		DynamicTab._jQueryInterface = function (config) {
			var $elem = $(this);
			var data = $elem.data(DATA_KEY);
			if (!data) {
				data = new DynamicTab(this, config);
				$elem.data(DATA_KEY, data);
			}

			return data;
		};

		return DynamicTab;
	}();

	$.fn[NAME] = DynamicTab._jQueryInterface;
	$.fn[NAME].Constructor = DynamicTab;
	$.fn[NAME].noConflict = function () {
		$.fn[NAME] = JQUERY_NO_CONFLICT;
		return DynamicTab._jQueryInterface;
	};
	return DynamicTab;
}(jQuery);
